/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * AdaboostM1SettingsPanel.java
 *
 * Created on Dec 11, 2009, 1:33:23 PM
 */

package wekinator.LearningAlgorithms;

import java.awt.CardLayout;
import javax.swing.JPanel;
import weka.classifiers.functions.SMO;
import weka.classifiers.functions.supportVector.Kernel;
import weka.classifiers.functions.supportVector.PolyKernel;
import weka.classifiers.functions.supportVector.RBFKernel;

/**
 *
 * @author rebecca
 */
public class SMOSettingsPanel extends javax.swing.JPanel implements LearningAlgorithmSettingsPanel {

    SMOLearningAlgorithm la = null;
    Kernel oldOtherKernel = null;

    /** Creates new form AdaboostM1SettingsPanel */
    public SMOSettingsPanel() {
        initComponents();
    }

    public SMOSettingsPanel(SMOLearningAlgorithm la) {
        initComponents();
        setLearningAlgorithm(la);
    }

    public void setLearningAlgorithm(SMOLearningAlgorithm la) {
        this.la = la;
        setKernel();
        textC.setText(la.getClassifier().getC() + "");
    }


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        panelKernelParent = new javax.swing.JPanel();
        panelPolyKernel = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        checkPolyLower = new javax.swing.JCheckBox();
        textPolyExponent = new javax.swing.JTextField();
        panelLinearKernel = new javax.swing.JPanel();
        panelRBFKernel = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        textRbfGamma = new javax.swing.JTextField();
        panelOtherKernel = new javax.swing.JPanel();
        comboKernel = new javax.swing.JComboBox();
        jLabel3 = new javax.swing.JLabel();
        jLabel4 = new javax.swing.JLabel();
        textC = new javax.swing.JTextField();

        panelKernelParent.setLayout(new java.awt.CardLayout());

        jLabel1.setText("Exponent:");

        checkPolyLower.setText("Use lower-order terms");
        checkPolyLower.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
        checkPolyLower.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                checkPolyLowerActionPerformed(evt);
            }
        });

        textPolyExponent.setText("2.0");

        org.jdesktop.layout.GroupLayout panelPolyKernelLayout = new org.jdesktop.layout.GroupLayout(panelPolyKernel);
        panelPolyKernel.setLayout(panelPolyKernelLayout);
        panelPolyKernelLayout.setHorizontalGroup(
            panelPolyKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(panelPolyKernelLayout.createSequentialGroup()
                .add(jLabel1)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(textPolyExponent, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 44, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
            .add(checkPolyLower)
        );
        panelPolyKernelLayout.setVerticalGroup(
            panelPolyKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(panelPolyKernelLayout.createSequentialGroup()
                .add(panelPolyKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel1)
                    .add(textPolyExponent, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 28, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(checkPolyLower))
        );

        panelKernelParent.add(panelPolyKernel, "polynomial");

        org.jdesktop.layout.GroupLayout panelLinearKernelLayout = new org.jdesktop.layout.GroupLayout(panelLinearKernel);
        panelLinearKernel.setLayout(panelLinearKernelLayout);
        panelLinearKernelLayout.setHorizontalGroup(
            panelLinearKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 223, Short.MAX_VALUE)
        );
        panelLinearKernelLayout.setVerticalGroup(
            panelLinearKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 55, Short.MAX_VALUE)
        );

        panelKernelParent.add(panelLinearKernel, "linear");

        jLabel2.setText("Gamma:");

        textRbfGamma.setText(".01");

        org.jdesktop.layout.GroupLayout panelRBFKernelLayout = new org.jdesktop.layout.GroupLayout(panelRBFKernel);
        panelRBFKernel.setLayout(panelRBFKernelLayout);
        panelRBFKernelLayout.setHorizontalGroup(
            panelRBFKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(panelRBFKernelLayout.createSequentialGroup()
                .add(jLabel2)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(textRbfGamma, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 44, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(118, Short.MAX_VALUE))
        );
        panelRBFKernelLayout.setVerticalGroup(
            panelRBFKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(panelRBFKernelLayout.createSequentialGroup()
                .add(panelRBFKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel2)
                    .add(textRbfGamma, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 28, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(27, Short.MAX_VALUE))
        );

        panelKernelParent.add(panelRBFKernel, "rbf");

        org.jdesktop.layout.GroupLayout panelOtherKernelLayout = new org.jdesktop.layout.GroupLayout(panelOtherKernel);
        panelOtherKernel.setLayout(panelOtherKernelLayout);
        panelOtherKernelLayout.setHorizontalGroup(
            panelOtherKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 223, Short.MAX_VALUE)
        );
        panelOtherKernelLayout.setVerticalGroup(
            panelOtherKernelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 55, Short.MAX_VALUE)
        );

        panelKernelParent.add(panelOtherKernel, "other");

        comboKernel.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Linear", "Polynomial", "RBF" }));
        comboKernel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                comboKernelActionPerformed(evt);
            }
        });

        jLabel3.setText("Kernel:");

        jLabel4.setText("Complexity constant:");

        textC.setText("1.0");

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(layout.createSequentialGroup()
                        .add(jLabel3)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(comboKernel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(layout.createSequentialGroup()
                        .add(11, 11, 11)
                        .add(panelKernelParent, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                    .add(layout.createSequentialGroup()
                        .add(jLabel4)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(textC, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 44, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel3)
                    .add(comboKernel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(panelKernelParent, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel4)
                    .add(textC, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void checkPolyLowerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_checkPolyLowerActionPerformed
        // TODO add your handling code here:
}//GEN-LAST:event_checkPolyLowerActionPerformed

    private void comboKernelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_comboKernelActionPerformed
        int i = comboKernel.getSelectedIndex();
        setKernelIndex(i);
    }//GEN-LAST:event_comboKernelActionPerformed

    protected void setKernelIndex(int i) {
        CardLayout l = (CardLayout) panelKernelParent.getLayout();
        if (i == 0) {
            l.show(panelKernelParent, "linear");
        } else if (i == 1) {
            l.show(panelKernelParent, "polynomial");
        } else if (i == 2) {
            l.show(panelKernelParent, "rbf");
        } else {
            l.show(panelKernelParent, "other");
        }
    }

    public void applySettings() throws Exception {
        boolean valid = true;
        Kernel k = null;
        double c = 0;
        double g = 0.0;
        double e = 0.0;
        String s = "";
        int kIndex =0;
        try {
            c = Double.parseDouble(textC.getText());
            if (c <= 0) 
            {
                throw new Exception("Invalid complexity constant " + c);
            }

            kIndex = comboKernel.getSelectedIndex();
            /* if (kIndex == 0) {
                //no other checking needed
            } */
            if (kIndex == 1) {
                e = Double.parseDouble(textPolyExponent.getText());
                if (e <= 0)
                    throw new Exception ("Invalid polynomial exponent " + e);
            } else if (kIndex == 2) {
                            g = Double.parseDouble(textRbfGamma.getText());
                if (g <= 0)
                    throw new Exception ("Invalid RBF gamma " + g); //TODO: check what's actually appropriate for each kernel

            } /*else if (kIndex == 3) {
                //nothing else to do.
            } */
        } catch (Exception ex) {
            throw new Exception(ex);
        }

        //ok, now valid for sure.
        la.getClassifier().setC(c);
       // la.getClassifier().setC


        if (kIndex == 3) {
            la.getClassifier().setKernel(oldOtherKernel);
        } else if (kIndex == 0) {
            la.setLinearKernel();
        } else if (kIndex == 1) {
            la.setPolyKernel(e, checkPolyLower.isSelected());
        } else if (kIndex == 2) {
            la.setRbfKernel(g);
        }
    }
    
    public void reset() {
        setKernel();
        textC.setText(la.getClassifier().getC() + "");
    }

    public JPanel getPanel() {
        return this;
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBox checkPolyLower;
    private javax.swing.JComboBox comboKernel;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JPanel panelKernelParent;
    private javax.swing.JPanel panelLinearKernel;
    private javax.swing.JPanel panelOtherKernel;
    private javax.swing.JPanel panelPolyKernel;
    private javax.swing.JPanel panelRBFKernel;
    private javax.swing.JTextField textC;
    private javax.swing.JTextField textPolyExponent;
    private javax.swing.JTextField textRbfGamma;
    // End of variables declaration//GEN-END:variables

    private void setKernel() {
        SMO s = la.getClassifier();
        Kernel k = s.getKernel();
        if (k instanceof PolyKernel) {
            double e = ((PolyKernel)k).getExponent();
            if (e == 1.0) {
                comboKernel.setSelectedIndex(0);
                setKernelIndex(0);
            } else {
                comboKernel.setSelectedIndex(1);
                setKernelIndex(1);
                textPolyExponent.setText(e + "");
                checkPolyLower.setSelected(((PolyKernel)k).getUseLowerOrder());
            }
        } else if (k instanceof RBFKernel) {
            comboKernel.setSelectedIndex(2);
            setKernelIndex(2);
            textRbfGamma.setText(((RBFKernel)k).getGamma() + "");
        } else {
            if (comboKernel.getItemCount() == 3) {
                //add a new one
                comboKernel.addItem("Original other kernel"); //TODO: test this
                oldOtherKernel = k;
            }
            comboKernel.setSelectedIndex(3);
            setKernelIndex(3);
        }
    }

}
